package com.motu.monstercity.server.login.verticle;

import com.motu.monstercity.module.common.redis.RedisKey;
import com.motu.monstercity.module.common.servermanager.ServerManager;
import com.motu.monstercity.module.common.utility.ServerParam;
import com.motu.monstercity.module.common.verticle.GmVerticle;
import com.motu.monstercity.protocol.CommonHttp.PBRoleInfo;
import com.motu.monstercity.server.login.iap.LoginIapManager;
import com.motu.monstercity.server.login.notice.NoticeManager;
import com.motu.vertx.module.utility.main.MainService;
import com.motu.vertx.module.utility.model.EntityManager;
import com.motu.vertx.module.utility.mysql.MysqlClient;
import com.motu.vertx.module.utility.mysql.MysqlTool;
import com.motu.vertx.module.utility.redis.RedisTools;
import com.motu.vertx.module.utility.toolset.TimeUtils;
import com.motu.vertx.module.utility.toolset.Tool;
import com.motu.vertx.module.utility.vertx.VerticleTool;
import io.vertx.core.*;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;

public class MainVerticle extends AbstractVerticle {

    public static final Logger logger = LoggerFactory.getLogger(MainVerticle.class);

    @Override
    public void start(Promise<Void> startPromise) throws Exception {

        // 需要在这里获取配置，在startVerticle中通过config()获取不到
        JsonObject config = config();
        // 启动入口方法
        AbstractVerticle startVerticle = new AbstractVerticle() {
            @Override
            public void start() {
                logger.info("Login MainVerticle start");

                try {

                    // 初始化公共服务
					MainService.init(vertx, config);

                    // 初始化游戏基础配置数据
                    Future.await(initBaseData());

                    // 部署游戏业务Verticle
                    Future.await(deployVerticles());

                    logger.info("Login MainVerticle start success!!!");
                    startPromise.complete();

                } catch (Throwable t) {
                    /** 虚拟线程返回错误需要用Throwable才可以捕捉到异常 **/
                    logger.error("Login MainVerticle start error cause:{}", Tool.getException(t));
                    startPromise.fail(t);
                }

            }
        };

        // Run the verticle a on virtual thread
        vertx.deployVerticle(startVerticle, new DeploymentOptions().setThreadingModel(ThreadingModel.VIRTUAL_THREAD))
                .onComplete(res -> {
                    if (res.succeeded()) {
                        System.out.println("Login startVerticle Deployment success id is: " + res.result());

						// 部署GmVerticle gm都要部署,用来重载,检测集群等（这个要最后部署，这样启动失败就无法检测集群）
						VerticleTool.deployVerticleIfNeeded(vertx, GmVerticle.class.getName(), VerticleTool.getDeploymentOptions("gm-verticle-instances", 1, ThreadingModel.VIRTUAL_THREAD));
                    } else {
                        System.out.println("Login startVerticle Deployment failed:" + res.cause());
                    }
                });

    }

    /**
     * 初始化游戏基础配置数据
     */
    public Future<Void> initBaseData() {
        Promise<Void> promise = Promise.promise();
        List<Future> futureList = new ArrayList<>();

        NoticeManager.init(futureList);// 初始化公告
        ServerManager.init(futureList);// 初始化服务器信息
        LoginIapManager.init(futureList);// 初始化iap信息

        CompositeFuture.all(futureList).onComplete(hanler->{
            if (hanler.succeeded()) {
                promise.complete();
            } else {
                promise.fail(hanler.cause());
            }
        });
        return promise.future();
    }

    public Future<Long> incrTableId(String key) {
        Promise<Long> promise = Promise.promise();
        long initId = ServerParam.TABLE_INIT_ID;
        RedisTools.hsetnx(RedisTools.getTableidKey(), key, String.valueOf(initId), h -> {
            if (h.succeeded()) {
                if (h.result()) {
                    logger.info("### table = " + key + " init id = " + initId);
                    promise.complete(initId);
                } else {
                    RedisTools.incrTableId(key, h2 -> {
                        if (h2.succeeded()) {
                            promise.complete(h2.result());
                        } else {
                            promise.fail(h2.cause());
                        }
                    });
                }
            } else {
                promise.fail(h.cause());
            }
        });
        return promise.future();
    }

    // 手动创建角色,测试用
    public void creatRole() {
        // 创建用户信息
        logger.info("### creat role start!!!");
        long userId = Future.await(incrTableId("user_info"));
        int serverId = 1001;
        String sqlInsert = "INSERT INTO user_info(id,server_id,user_name,icon,location) VALUES(?,?,?,?,?);";
        JsonArray paramsInsert = new JsonArray();
        paramsInsert.add(userId);
        paramsInsert.add(serverId);
        paramsInsert.add("");
        paramsInsert.add(0);
        paramsInsert.add(0);
        Future.await(MysqlTool.updateToDb(MysqlClient.getGamePool(), sqlInsert, paramsInsert));

        String account = "186461f7737f4154a4c17e7b1578b80a";
        int accountType = 8;
        int platform = 1;
        long channel = 0;
        String sqlInsert2 = "insert into user_ext_info(id,server_id,account_id,account_type,platform,channel,device_id,ip,register_time,mob_id) "
                + "values(?,?,?,?,?,?,?,?,?,?);";
        JsonArray paramsInsert2 = new JsonArray();
        paramsInsert2.add(userId);
        paramsInsert2.add(serverId);
        paramsInsert2.add(account);
        paramsInsert2.add(accountType);
        paramsInsert2.add(platform);
        paramsInsert2.add(channel);
        paramsInsert2.add("");
        paramsInsert2.add("");
        paramsInsert2.add(TimeUtils.getCurTime());
        paramsInsert2.add(0);
        Future.await(MysqlTool.updateToDb(MysqlClient.getGamePool(), sqlInsert2, paramsInsert2));

        // 把userinfo和userextinfo添加到redis中
        String strUserinfoKey = RedisKey.getUserInfoKey(userId);
        JsonObject objUserinfo = new JsonObject();
        objUserinfo.put("id", userId);
        objUserinfo.put("serverId", serverId);
        objUserinfo.put("userName", "");
        objUserinfo.put("location", 0);
        Future.await(RedisTools.setHashJsonObject(strUserinfoKey, objUserinfo));
        // 标记数据已经初始化
        Future.await(RedisTools.set(EntityManager.getEntityInitKey(strUserinfoKey), "1"));

        String strUserextinfoKey = RedisKey.getUserExtInfoKey(userId);
        JsonObject objUserextinfo = new JsonObject();
        objUserextinfo.put("id", userId);
        objUserextinfo.put("serverId", serverId);
        objUserextinfo.put("accountId", account);
        objUserextinfo.put("platform", platform);
        objUserextinfo.put("channel", channel);
        objUserextinfo.put("deviceId", "");
        objUserextinfo.put("ip", "");
        objUserextinfo.put("registerTime", TimeUtils.getCurTime());
        objUserextinfo.put("language", 1);
        objUserextinfo.put("accountType", accountType);
        objUserextinfo.put("mobId", "");
        Future.await(RedisTools.setHashJsonObject(strUserextinfoKey, objUserextinfo));
        // 标记数据已经初始化
        Future.await(RedisTools.set(EntityManager.getEntityInitKey(strUserextinfoKey), "1"));
    }

    /**
     * 部署游戏业务Verticle
     */
    public Future<Void> deployVerticles() {
        Promise promise = Promise.promise();

        List<Future<?>> list = new ArrayList<>();
        list.add(VerticleTool.deployVerticleIfNeeded(vertx, HttpVerticle.class.getName(), VerticleTool.getDeploymentOptions("http-verticle-instances", 8, ThreadingModel.VIRTUAL_THREAD)));
        list.add(VerticleTool.deployVerticleIfNeeded(vertx, GetipVerticle.class.getName(), VerticleTool.getDeploymentOptions("http-verticle-instances", 1, ThreadingModel.VIRTUAL_THREAD)));
        list.add(VerticleTool.deployVerticleIfNeeded(vertx, LoginMonitorVerticle.class.getName(), VerticleTool.getDeploymentOptions("monitor-verticle-instances", 1, ThreadingModel.VIRTUAL_THREAD)));

        Future.all(list).onComplete(promise);

        return promise.future();
    }

}
